Add dataloader and read from cache for view entities (#18594)
## Context Improve view resolution using cache and dataloader ## Performance Comparison |Run|Main (no DataLoaders/cache)|Feature Branch (DataLoaders + cache)|Speedup| |---|---|---|---| |1 (cold)|418ms|95ms|~4.4x faster| |2|42ms|19ms|~2.2x faster| |3|37ms|19ms|~1.9x faster| |4|39ms|12ms|~3.2x faster| |5|33ms|13ms|~2.5x faster| The biggest improvement is to use dataloaders for the multiple relations associated with views. Cache is a bit less significant since there are other cache mechanism such as PostgreSQL buffer cache but it will probably be more meaningful with bigger workspaces
This commit is contained in:
@@ -2885,12 +2885,6 @@ type Query {
|
||||
getCoreView(id: String!): CoreView
|
||||
getCoreViewSorts(viewId: String): [CoreViewSort!]!
|
||||
getCoreViewSort(id: String!): CoreViewSort
|
||||
getCoreViewGroups(viewId: String): [CoreViewGroup!]!
|
||||
getCoreViewGroup(id: String!): CoreViewGroup
|
||||
getCoreViewFilterGroups(viewId: String): [CoreViewFilterGroup!]!
|
||||
getCoreViewFilterGroup(id: String!): CoreViewFilterGroup
|
||||
getCoreViewFilters(viewId: String): [CoreViewFilter!]!
|
||||
getCoreViewFilter(id: String!): CoreViewFilter
|
||||
getCoreViewFieldGroups(viewId: String!): [CoreViewFieldGroup!]!
|
||||
getCoreViewFieldGroup(id: String!): CoreViewFieldGroup
|
||||
index(
|
||||
@@ -2936,6 +2930,12 @@ type Query {
|
||||
"""Specify to filter the records returned."""
|
||||
filter: FieldFilter! = {}
|
||||
): FieldConnection!
|
||||
getCoreViewGroups(viewId: String): [CoreViewGroup!]!
|
||||
getCoreViewGroup(id: String!): CoreViewGroup
|
||||
getCoreViewFilters(viewId: String): [CoreViewFilter!]!
|
||||
getCoreViewFilter(id: String!): CoreViewFilter
|
||||
getCoreViewFilterGroups(viewId: String): [CoreViewFilterGroup!]!
|
||||
getCoreViewFilterGroup(id: String!): CoreViewFilterGroup
|
||||
currentUser: User!
|
||||
currentWorkspace: Workspace!
|
||||
getPublicWorkspaceDataByDomain(origin: String): PublicWorkspaceData!
|
||||
@@ -3134,19 +3134,6 @@ type Mutation {
|
||||
updateCoreViewSort(input: UpdateViewSortInput!): CoreViewSort!
|
||||
deleteCoreViewSort(input: DeleteViewSortInput!): Boolean!
|
||||
destroyCoreViewSort(input: DestroyViewSortInput!): Boolean!
|
||||
createCoreViewGroup(input: CreateViewGroupInput!): CoreViewGroup!
|
||||
createManyCoreViewGroups(inputs: [CreateViewGroupInput!]!): [CoreViewGroup!]!
|
||||
updateCoreViewGroup(input: UpdateViewGroupInput!): CoreViewGroup!
|
||||
deleteCoreViewGroup(input: DeleteViewGroupInput!): CoreViewGroup!
|
||||
destroyCoreViewGroup(input: DestroyViewGroupInput!): CoreViewGroup!
|
||||
createCoreViewFilterGroup(input: CreateViewFilterGroupInput!): CoreViewFilterGroup!
|
||||
updateCoreViewFilterGroup(id: String!, input: UpdateViewFilterGroupInput!): CoreViewFilterGroup!
|
||||
deleteCoreViewFilterGroup(id: String!): Boolean!
|
||||
destroyCoreViewFilterGroup(id: String!): Boolean!
|
||||
createCoreViewFilter(input: CreateViewFilterInput!): CoreViewFilter!
|
||||
updateCoreViewFilter(input: UpdateViewFilterInput!): CoreViewFilter!
|
||||
deleteCoreViewFilter(input: DeleteViewFilterInput!): CoreViewFilter!
|
||||
destroyCoreViewFilter(input: DestroyViewFilterInput!): CoreViewFilter!
|
||||
updateCoreViewFieldGroup(input: UpdateViewFieldGroupInput!): CoreViewFieldGroup!
|
||||
createCoreViewFieldGroup(input: CreateViewFieldGroupInput!): CoreViewFieldGroup!
|
||||
createManyCoreViewFieldGroups(inputs: [CreateViewFieldGroupInput!]!): [CoreViewFieldGroup!]!
|
||||
@@ -3206,6 +3193,19 @@ type Mutation {
|
||||
createOneField(input: CreateOneFieldMetadataInput!): Field!
|
||||
updateOneField(input: UpdateOneFieldMetadataInput!): Field!
|
||||
deleteOneField(input: DeleteOneFieldInput!): Field!
|
||||
createCoreViewGroup(input: CreateViewGroupInput!): CoreViewGroup!
|
||||
createManyCoreViewGroups(inputs: [CreateViewGroupInput!]!): [CoreViewGroup!]!
|
||||
updateCoreViewGroup(input: UpdateViewGroupInput!): CoreViewGroup!
|
||||
deleteCoreViewGroup(input: DeleteViewGroupInput!): CoreViewGroup!
|
||||
destroyCoreViewGroup(input: DestroyViewGroupInput!): CoreViewGroup!
|
||||
createCoreViewFilter(input: CreateViewFilterInput!): CoreViewFilter!
|
||||
updateCoreViewFilter(input: UpdateViewFilterInput!): CoreViewFilter!
|
||||
deleteCoreViewFilter(input: DeleteViewFilterInput!): CoreViewFilter!
|
||||
destroyCoreViewFilter(input: DestroyViewFilterInput!): CoreViewFilter!
|
||||
createCoreViewFilterGroup(input: CreateViewFilterGroupInput!): CoreViewFilterGroup!
|
||||
updateCoreViewFilterGroup(id: String!, input: UpdateViewFilterGroupInput!): CoreViewFilterGroup!
|
||||
deleteCoreViewFilterGroup(id: String!): Boolean!
|
||||
destroyCoreViewFilterGroup(id: String!): Boolean!
|
||||
deleteUser: User!
|
||||
deleteUserFromWorkspace(workspaceMemberIdToDelete: String!): UserWorkspace!
|
||||
updateUserEmail(newEmail: String!, verifyEmailRedirectPath: String): Boolean!
|
||||
@@ -3581,93 +3581,6 @@ input DestroyViewSortInput {
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input CreateViewGroupInput {
|
||||
id: UUID
|
||||
isVisible: Boolean = true
|
||||
fieldValue: String!
|
||||
position: Float = 0
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewGroupInput {
|
||||
"""The id of the view group to update"""
|
||||
id: UUID!
|
||||
|
||||
"""The view group to update"""
|
||||
update: UpdateViewGroupInputUpdates!
|
||||
}
|
||||
|
||||
input UpdateViewGroupInputUpdates {
|
||||
fieldMetadataId: UUID
|
||||
isVisible: Boolean
|
||||
fieldValue: String
|
||||
position: Float
|
||||
}
|
||||
|
||||
input DeleteViewGroupInput {
|
||||
"""The id of the view group to delete."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input DestroyViewGroupInput {
|
||||
"""The id of the view group to destroy."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input CreateViewFilterGroupInput {
|
||||
id: UUID
|
||||
parentViewFilterGroupId: UUID
|
||||
logicalOperator: ViewFilterGroupLogicalOperator = AND
|
||||
positionInViewFilterGroup: Float
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewFilterGroupInput {
|
||||
id: UUID
|
||||
parentViewFilterGroupId: UUID
|
||||
logicalOperator: ViewFilterGroupLogicalOperator = AND
|
||||
positionInViewFilterGroup: Float
|
||||
viewId: UUID
|
||||
}
|
||||
|
||||
input CreateViewFilterInput {
|
||||
id: UUID
|
||||
fieldMetadataId: UUID!
|
||||
operand: ViewFilterOperand = CONTAINS
|
||||
value: JSON!
|
||||
viewFilterGroupId: UUID
|
||||
positionInViewFilterGroup: Float
|
||||
subFieldName: String
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewFilterInput {
|
||||
"""The id of the view filter to update"""
|
||||
id: UUID!
|
||||
|
||||
"""The view filter to update"""
|
||||
update: UpdateViewFilterInputUpdates!
|
||||
}
|
||||
|
||||
input UpdateViewFilterInputUpdates {
|
||||
fieldMetadataId: UUID
|
||||
operand: ViewFilterOperand
|
||||
value: JSON
|
||||
viewFilterGroupId: UUID
|
||||
positionInViewFilterGroup: Float
|
||||
subFieldName: String
|
||||
}
|
||||
|
||||
input DeleteViewFilterInput {
|
||||
"""The id of the view filter to delete."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input DestroyViewFilterInput {
|
||||
"""The id of the view filter to destroy."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewFieldGroupInput {
|
||||
"""The id of the view field group to update"""
|
||||
id: UUID!
|
||||
@@ -4025,6 +3938,93 @@ input DeleteOneFieldInput {
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input CreateViewGroupInput {
|
||||
id: UUID
|
||||
isVisible: Boolean = true
|
||||
fieldValue: String!
|
||||
position: Float = 0
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewGroupInput {
|
||||
"""The id of the view group to update"""
|
||||
id: UUID!
|
||||
|
||||
"""The view group to update"""
|
||||
update: UpdateViewGroupInputUpdates!
|
||||
}
|
||||
|
||||
input UpdateViewGroupInputUpdates {
|
||||
fieldMetadataId: UUID
|
||||
isVisible: Boolean
|
||||
fieldValue: String
|
||||
position: Float
|
||||
}
|
||||
|
||||
input DeleteViewGroupInput {
|
||||
"""The id of the view group to delete."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input DestroyViewGroupInput {
|
||||
"""The id of the view group to destroy."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input CreateViewFilterInput {
|
||||
id: UUID
|
||||
fieldMetadataId: UUID!
|
||||
operand: ViewFilterOperand = CONTAINS
|
||||
value: JSON!
|
||||
viewFilterGroupId: UUID
|
||||
positionInViewFilterGroup: Float
|
||||
subFieldName: String
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewFilterInput {
|
||||
"""The id of the view filter to update"""
|
||||
id: UUID!
|
||||
|
||||
"""The view filter to update"""
|
||||
update: UpdateViewFilterInputUpdates!
|
||||
}
|
||||
|
||||
input UpdateViewFilterInputUpdates {
|
||||
fieldMetadataId: UUID
|
||||
operand: ViewFilterOperand
|
||||
value: JSON
|
||||
viewFilterGroupId: UUID
|
||||
positionInViewFilterGroup: Float
|
||||
subFieldName: String
|
||||
}
|
||||
|
||||
input DeleteViewFilterInput {
|
||||
"""The id of the view filter to delete."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input DestroyViewFilterInput {
|
||||
"""The id of the view filter to destroy."""
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
input CreateViewFilterGroupInput {
|
||||
id: UUID
|
||||
parentViewFilterGroupId: UUID
|
||||
logicalOperator: ViewFilterGroupLogicalOperator = AND
|
||||
positionInViewFilterGroup: Float
|
||||
viewId: UUID!
|
||||
}
|
||||
|
||||
input UpdateViewFilterGroupInput {
|
||||
id: UUID
|
||||
parentViewFilterGroupId: UUID
|
||||
logicalOperator: ViewFilterGroupLogicalOperator = AND
|
||||
positionInViewFilterGroup: Float
|
||||
viewId: UUID
|
||||
}
|
||||
|
||||
input ActivateWorkspaceInput {
|
||||
displayName: String
|
||||
}
|
||||
|
||||
@@ -2543,12 +2543,6 @@ export interface Query {
|
||||
getCoreView?: CoreView
|
||||
getCoreViewSorts: CoreViewSort[]
|
||||
getCoreViewSort?: CoreViewSort
|
||||
getCoreViewGroups: CoreViewGroup[]
|
||||
getCoreViewGroup?: CoreViewGroup
|
||||
getCoreViewFilterGroups: CoreViewFilterGroup[]
|
||||
getCoreViewFilterGroup?: CoreViewFilterGroup
|
||||
getCoreViewFilters: CoreViewFilter[]
|
||||
getCoreViewFilter?: CoreViewFilter
|
||||
getCoreViewFieldGroups: CoreViewFieldGroup[]
|
||||
getCoreViewFieldGroup?: CoreViewFieldGroup
|
||||
index: Index
|
||||
@@ -2576,6 +2570,12 @@ export interface Query {
|
||||
getToolInputSchema?: Scalars['JSON']
|
||||
field: Field
|
||||
fields: FieldConnection
|
||||
getCoreViewGroups: CoreViewGroup[]
|
||||
getCoreViewGroup?: CoreViewGroup
|
||||
getCoreViewFilters: CoreViewFilter[]
|
||||
getCoreViewFilter?: CoreViewFilter
|
||||
getCoreViewFilterGroups: CoreViewFilterGroup[]
|
||||
getCoreViewFilterGroup?: CoreViewFilterGroup
|
||||
currentUser: User
|
||||
currentWorkspace: Workspace
|
||||
getPublicWorkspaceDataByDomain: PublicWorkspaceData
|
||||
@@ -2673,19 +2673,6 @@ export interface Mutation {
|
||||
updateCoreViewSort: CoreViewSort
|
||||
deleteCoreViewSort: Scalars['Boolean']
|
||||
destroyCoreViewSort: Scalars['Boolean']
|
||||
createCoreViewGroup: CoreViewGroup
|
||||
createManyCoreViewGroups: CoreViewGroup[]
|
||||
updateCoreViewGroup: CoreViewGroup
|
||||
deleteCoreViewGroup: CoreViewGroup
|
||||
destroyCoreViewGroup: CoreViewGroup
|
||||
createCoreViewFilterGroup: CoreViewFilterGroup
|
||||
updateCoreViewFilterGroup: CoreViewFilterGroup
|
||||
deleteCoreViewFilterGroup: Scalars['Boolean']
|
||||
destroyCoreViewFilterGroup: Scalars['Boolean']
|
||||
createCoreViewFilter: CoreViewFilter
|
||||
updateCoreViewFilter: CoreViewFilter
|
||||
deleteCoreViewFilter: CoreViewFilter
|
||||
destroyCoreViewFilter: CoreViewFilter
|
||||
updateCoreViewFieldGroup: CoreViewFieldGroup
|
||||
createCoreViewFieldGroup: CoreViewFieldGroup
|
||||
createManyCoreViewFieldGroups: CoreViewFieldGroup[]
|
||||
@@ -2745,6 +2732,19 @@ export interface Mutation {
|
||||
createOneField: Field
|
||||
updateOneField: Field
|
||||
deleteOneField: Field
|
||||
createCoreViewGroup: CoreViewGroup
|
||||
createManyCoreViewGroups: CoreViewGroup[]
|
||||
updateCoreViewGroup: CoreViewGroup
|
||||
deleteCoreViewGroup: CoreViewGroup
|
||||
destroyCoreViewGroup: CoreViewGroup
|
||||
createCoreViewFilter: CoreViewFilter
|
||||
updateCoreViewFilter: CoreViewFilter
|
||||
deleteCoreViewFilter: CoreViewFilter
|
||||
destroyCoreViewFilter: CoreViewFilter
|
||||
createCoreViewFilterGroup: CoreViewFilterGroup
|
||||
updateCoreViewFilterGroup: CoreViewFilterGroup
|
||||
deleteCoreViewFilterGroup: Scalars['Boolean']
|
||||
destroyCoreViewFilterGroup: Scalars['Boolean']
|
||||
deleteUser: User
|
||||
deleteUserFromWorkspace: UserWorkspace
|
||||
updateUserEmail: Scalars['Boolean']
|
||||
@@ -5552,12 +5552,6 @@ export interface QueryGenqlSelection{
|
||||
getCoreView?: (CoreViewGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewSorts?: (CoreViewSortGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewSort?: (CoreViewSortGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewGroups?: (CoreViewGroupGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewFilterGroups?: (CoreViewFilterGroupGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewFilterGroup?: (CoreViewFilterGroupGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewFilters?: (CoreViewFilterGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewFieldGroups?: (CoreViewFieldGroupGenqlSelection & { __args: {viewId: Scalars['String']} })
|
||||
getCoreViewFieldGroup?: (CoreViewFieldGroupGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
index?: (IndexGenqlSelection & { __args: {
|
||||
@@ -5597,6 +5591,12 @@ export interface QueryGenqlSelection{
|
||||
paging: CursorPaging,
|
||||
/** Specify to filter the records returned. */
|
||||
filter: FieldFilter} })
|
||||
getCoreViewGroups?: (CoreViewGroupGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewFilters?: (CoreViewFilterGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
getCoreViewFilterGroups?: (CoreViewFilterGroupGenqlSelection & { __args?: {viewId?: (Scalars['String'] | null)} })
|
||||
getCoreViewFilterGroup?: (CoreViewFilterGroupGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
currentUser?: UserGenqlSelection
|
||||
currentWorkspace?: WorkspaceGenqlSelection
|
||||
getPublicWorkspaceDataByDomain?: (PublicWorkspaceDataGenqlSelection & { __args?: {origin?: (Scalars['String'] | null)} })
|
||||
@@ -5719,19 +5719,6 @@ export interface MutationGenqlSelection{
|
||||
updateCoreViewSort?: (CoreViewSortGenqlSelection & { __args: {input: UpdateViewSortInput} })
|
||||
deleteCoreViewSort?: { __args: {input: DeleteViewSortInput} }
|
||||
destroyCoreViewSort?: { __args: {input: DestroyViewSortInput} }
|
||||
createCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: CreateViewGroupInput} })
|
||||
createManyCoreViewGroups?: (CoreViewGroupGenqlSelection & { __args: {inputs: CreateViewGroupInput[]} })
|
||||
updateCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: UpdateViewGroupInput} })
|
||||
deleteCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: DeleteViewGroupInput} })
|
||||
destroyCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: DestroyViewGroupInput} })
|
||||
createCoreViewFilterGroup?: (CoreViewFilterGroupGenqlSelection & { __args: {input: CreateViewFilterGroupInput} })
|
||||
updateCoreViewFilterGroup?: (CoreViewFilterGroupGenqlSelection & { __args: {id: Scalars['String'], input: UpdateViewFilterGroupInput} })
|
||||
deleteCoreViewFilterGroup?: { __args: {id: Scalars['String']} }
|
||||
destroyCoreViewFilterGroup?: { __args: {id: Scalars['String']} }
|
||||
createCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: CreateViewFilterInput} })
|
||||
updateCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: UpdateViewFilterInput} })
|
||||
deleteCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: DeleteViewFilterInput} })
|
||||
destroyCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: DestroyViewFilterInput} })
|
||||
updateCoreViewFieldGroup?: (CoreViewFieldGroupGenqlSelection & { __args: {input: UpdateViewFieldGroupInput} })
|
||||
createCoreViewFieldGroup?: (CoreViewFieldGroupGenqlSelection & { __args: {input: CreateViewFieldGroupInput} })
|
||||
createManyCoreViewFieldGroups?: (CoreViewFieldGroupGenqlSelection & { __args: {inputs: CreateViewFieldGroupInput[]} })
|
||||
@@ -5791,6 +5778,19 @@ export interface MutationGenqlSelection{
|
||||
createOneField?: (FieldGenqlSelection & { __args: {input: CreateOneFieldMetadataInput} })
|
||||
updateOneField?: (FieldGenqlSelection & { __args: {input: UpdateOneFieldMetadataInput} })
|
||||
deleteOneField?: (FieldGenqlSelection & { __args: {input: DeleteOneFieldInput} })
|
||||
createCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: CreateViewGroupInput} })
|
||||
createManyCoreViewGroups?: (CoreViewGroupGenqlSelection & { __args: {inputs: CreateViewGroupInput[]} })
|
||||
updateCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: UpdateViewGroupInput} })
|
||||
deleteCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: DeleteViewGroupInput} })
|
||||
destroyCoreViewGroup?: (CoreViewGroupGenqlSelection & { __args: {input: DestroyViewGroupInput} })
|
||||
createCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: CreateViewFilterInput} })
|
||||
updateCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: UpdateViewFilterInput} })
|
||||
deleteCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: DeleteViewFilterInput} })
|
||||
destroyCoreViewFilter?: (CoreViewFilterGenqlSelection & { __args: {input: DestroyViewFilterInput} })
|
||||
createCoreViewFilterGroup?: (CoreViewFilterGroupGenqlSelection & { __args: {input: CreateViewFilterGroupInput} })
|
||||
updateCoreViewFilterGroup?: (CoreViewFilterGroupGenqlSelection & { __args: {id: Scalars['String'], input: UpdateViewFilterGroupInput} })
|
||||
deleteCoreViewFilterGroup?: { __args: {id: Scalars['String']} }
|
||||
destroyCoreViewFilterGroup?: { __args: {id: Scalars['String']} }
|
||||
deleteUser?: UserGenqlSelection
|
||||
deleteUserFromWorkspace?: (UserWorkspaceGenqlSelection & { __args: {workspaceMemberIdToDelete: Scalars['String']} })
|
||||
updateUserEmail?: { __args: {newEmail: Scalars['String'], verifyEmailRedirectPath?: (Scalars['String'] | null)} }
|
||||
@@ -5976,46 +5976,6 @@ export interface DestroyViewSortInput {
|
||||
/** The id of the view sort to destroy. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface CreateViewGroupInput {id?: (Scalars['UUID'] | null),isVisible?: (Scalars['Boolean'] | null),fieldValue: Scalars['String'],position?: (Scalars['Float'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewGroupInput {
|
||||
/** The id of the view group to update */
|
||||
id: Scalars['UUID'],
|
||||
/** The view group to update */
|
||||
update: UpdateViewGroupInputUpdates}
|
||||
|
||||
export interface UpdateViewGroupInputUpdates {fieldMetadataId?: (Scalars['UUID'] | null),isVisible?: (Scalars['Boolean'] | null),fieldValue?: (Scalars['String'] | null),position?: (Scalars['Float'] | null)}
|
||||
|
||||
export interface DeleteViewGroupInput {
|
||||
/** The id of the view group to delete. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface DestroyViewGroupInput {
|
||||
/** The id of the view group to destroy. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface CreateViewFilterGroupInput {id?: (Scalars['UUID'] | null),parentViewFilterGroupId?: (Scalars['UUID'] | null),logicalOperator?: (ViewFilterGroupLogicalOperator | null),positionInViewFilterGroup?: (Scalars['Float'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewFilterGroupInput {id?: (Scalars['UUID'] | null),parentViewFilterGroupId?: (Scalars['UUID'] | null),logicalOperator?: (ViewFilterGroupLogicalOperator | null),positionInViewFilterGroup?: (Scalars['Float'] | null),viewId?: (Scalars['UUID'] | null)}
|
||||
|
||||
export interface CreateViewFilterInput {id?: (Scalars['UUID'] | null),fieldMetadataId: Scalars['UUID'],operand?: (ViewFilterOperand | null),value: Scalars['JSON'],viewFilterGroupId?: (Scalars['UUID'] | null),positionInViewFilterGroup?: (Scalars['Float'] | null),subFieldName?: (Scalars['String'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewFilterInput {
|
||||
/** The id of the view filter to update */
|
||||
id: Scalars['UUID'],
|
||||
/** The view filter to update */
|
||||
update: UpdateViewFilterInputUpdates}
|
||||
|
||||
export interface UpdateViewFilterInputUpdates {fieldMetadataId?: (Scalars['UUID'] | null),operand?: (ViewFilterOperand | null),value?: (Scalars['JSON'] | null),viewFilterGroupId?: (Scalars['UUID'] | null),positionInViewFilterGroup?: (Scalars['Float'] | null),subFieldName?: (Scalars['String'] | null)}
|
||||
|
||||
export interface DeleteViewFilterInput {
|
||||
/** The id of the view filter to delete. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface DestroyViewFilterInput {
|
||||
/** The id of the view filter to destroy. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewFieldGroupInput {
|
||||
/** The id of the view field group to update */
|
||||
id: Scalars['UUID'],
|
||||
@@ -6130,6 +6090,46 @@ export interface DeleteOneFieldInput {
|
||||
/** The id of the field to delete. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface CreateViewGroupInput {id?: (Scalars['UUID'] | null),isVisible?: (Scalars['Boolean'] | null),fieldValue: Scalars['String'],position?: (Scalars['Float'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewGroupInput {
|
||||
/** The id of the view group to update */
|
||||
id: Scalars['UUID'],
|
||||
/** The view group to update */
|
||||
update: UpdateViewGroupInputUpdates}
|
||||
|
||||
export interface UpdateViewGroupInputUpdates {fieldMetadataId?: (Scalars['UUID'] | null),isVisible?: (Scalars['Boolean'] | null),fieldValue?: (Scalars['String'] | null),position?: (Scalars['Float'] | null)}
|
||||
|
||||
export interface DeleteViewGroupInput {
|
||||
/** The id of the view group to delete. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface DestroyViewGroupInput {
|
||||
/** The id of the view group to destroy. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface CreateViewFilterInput {id?: (Scalars['UUID'] | null),fieldMetadataId: Scalars['UUID'],operand?: (ViewFilterOperand | null),value: Scalars['JSON'],viewFilterGroupId?: (Scalars['UUID'] | null),positionInViewFilterGroup?: (Scalars['Float'] | null),subFieldName?: (Scalars['String'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewFilterInput {
|
||||
/** The id of the view filter to update */
|
||||
id: Scalars['UUID'],
|
||||
/** The view filter to update */
|
||||
update: UpdateViewFilterInputUpdates}
|
||||
|
||||
export interface UpdateViewFilterInputUpdates {fieldMetadataId?: (Scalars['UUID'] | null),operand?: (ViewFilterOperand | null),value?: (Scalars['JSON'] | null),viewFilterGroupId?: (Scalars['UUID'] | null),positionInViewFilterGroup?: (Scalars['Float'] | null),subFieldName?: (Scalars['String'] | null)}
|
||||
|
||||
export interface DeleteViewFilterInput {
|
||||
/** The id of the view filter to delete. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface DestroyViewFilterInput {
|
||||
/** The id of the view filter to destroy. */
|
||||
id: Scalars['UUID']}
|
||||
|
||||
export interface CreateViewFilterGroupInput {id?: (Scalars['UUID'] | null),parentViewFilterGroupId?: (Scalars['UUID'] | null),logicalOperator?: (ViewFilterGroupLogicalOperator | null),positionInViewFilterGroup?: (Scalars['Float'] | null),viewId: Scalars['UUID']}
|
||||
|
||||
export interface UpdateViewFilterGroupInput {id?: (Scalars['UUID'] | null),parentViewFilterGroupId?: (Scalars['UUID'] | null),logicalOperator?: (ViewFilterGroupLogicalOperator | null),positionInViewFilterGroup?: (Scalars['Float'] | null),viewId?: (Scalars['UUID'] | null)}
|
||||
|
||||
export interface ActivateWorkspaceInput {displayName?: (Scalars['String'] | null)}
|
||||
|
||||
export interface UpdateWorkspaceInput {subdomain?: (Scalars['String'] | null),customDomain?: (Scalars['String'] | null),displayName?: (Scalars['String'] | null),logo?: (Scalars['String'] | null),inviteHash?: (Scalars['String'] | null),isPublicInviteLinkEnabled?: (Scalars['Boolean'] | null),allowImpersonation?: (Scalars['Boolean'] | null),isGoogleAuthEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthEnabled?: (Scalars['Boolean'] | null),isPasswordAuthEnabled?: (Scalars['Boolean'] | null),isGoogleAuthBypassEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthBypassEnabled?: (Scalars['Boolean'] | null),isPasswordAuthBypassEnabled?: (Scalars['Boolean'] | null),defaultRoleId?: (Scalars['UUID'] | null),isTwoFactorAuthenticationEnforced?: (Scalars['Boolean'] | null),trashRetentionDays?: (Scalars['Float'] | null),eventLogRetentionDays?: (Scalars['Float'] | null),fastModel?: (Scalars['String'] | null),smartModel?: (Scalars['String'] | null),aiAdditionalInstructions?: (Scalars['String'] | null),editableProfileFields?: (Scalars['String'][] | null),autoEnableNewAiModels?: (Scalars['Boolean'] | null),disabledAiModelIds?: (Scalars['String'][] | null),enabledAiModelIds?: (Scalars['String'][] | null),useRecommendedModels?: (Scalars['Boolean'] | null)}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+11
-8
@@ -11,6 +11,7 @@ import {
|
||||
computeRecordGqlOperationFilter,
|
||||
convertViewFilterValueToString,
|
||||
getFilterTypeFromFieldType,
|
||||
isDefined,
|
||||
turnAnyFieldFilterIntoRecordGqlFilter,
|
||||
} from 'twenty-shared/utils';
|
||||
import { ObjectLiteral } from 'typeorm';
|
||||
@@ -23,8 +24,11 @@ import {
|
||||
CommonQueryRunnerExceptionCode,
|
||||
} from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
|
||||
import { STANDARD_ERROR_MESSAGE } from 'src/engine/api/common/common-query-runners/errors/standard-error-message.constant';
|
||||
import { GroupByDefinition } from 'src/engine/api/common/common-query-runners/types/group-by-definition.type';
|
||||
import { GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types';
|
||||
import { getGroupByDefinitions } from 'src/engine/api/common/common-query-runners/utils/get-group-by-definitions.util';
|
||||
import { getObjectAlias } from 'src/engine/api/common/common-query-runners/utils/get-object-alias-for-group-by.util';
|
||||
import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util';
|
||||
import { CommonBaseQueryRunnerContext } from 'src/engine/api/common/types/common-base-query-runner-context.type';
|
||||
import { CommonExtendedQueryRunnerContext } from 'src/engine/api/common/types/common-extended-query-runner-context.type';
|
||||
import { CommonGroupByOutputItem } from 'src/engine/api/common/types/common-group-by-output-item.type';
|
||||
@@ -36,10 +40,7 @@ import {
|
||||
} from 'src/engine/api/common/types/common-query-args.type';
|
||||
import { CommonSelectedFieldsResult } from 'src/engine/api/common/types/common-selected-fields-result.type';
|
||||
import { GraphqlQueryParser } from 'src/engine/api/graphql/graphql-query-runner/graphql-query-parsers/graphql-query.parser';
|
||||
import { GroupByDefinition } from 'src/engine/api/common/common-query-runners/types/group-by-definition.type';
|
||||
import { GroupByField } from 'src/engine/api/common/common-query-runners/types/group-by-field.types';
|
||||
import { formatResultWithGroupByDimensionValues } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/format-result-with-group-by-dimension-values.util';
|
||||
import { isGroupByRelationField } from 'src/engine/api/common/common-query-runners/utils/is-group-by-relation-field.util';
|
||||
import { parseGroupByArgs } from 'src/engine/api/graphql/graphql-query-runner/group-by/resolvers/utils/parse-group-by-args.util';
|
||||
import { GroupByWithRecordsService } from 'src/engine/api/graphql/graphql-query-runner/group-by/services/group-by-with-records.service';
|
||||
import { getGroupLimit } from 'src/engine/api/graphql/graphql-query-runner/group-by/utils/get-group-limit.util';
|
||||
@@ -53,7 +54,6 @@ import { isMorphOrRelationFlatFieldMetadata } from 'src/engine/metadata-modules/
|
||||
import { FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service';
|
||||
import { ViewFilterService } from 'src/engine/metadata-modules/view-filter/services/view-filter.service';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { WorkspaceSelectQueryBuilder } from 'src/engine/twenty-orm/repository/workspace-select-query-builder';
|
||||
import { formatColumnNameForRelationField } from 'src/engine/twenty-orm/utils/format-column-name-for-relation-field.util';
|
||||
@@ -263,16 +263,19 @@ export class CommonGroupByQueryRunnerService extends CommonBaseQueryRunnerServic
|
||||
},
|
||||
});
|
||||
|
||||
let view: ViewEntity | null = viewFilters[0]?.view;
|
||||
const viewFromFilter = viewFilters[0]?.view;
|
||||
let viewAnyFieldFilterValue = viewFromFilter?.anyFieldFilterValue;
|
||||
|
||||
if (!view) {
|
||||
view = await this.viewService.findById(args.viewId, workspaceId);
|
||||
if (!isDefined(viewFromFilter)) {
|
||||
const view = await this.viewService.findById(args.viewId, workspaceId);
|
||||
|
||||
viewAnyFieldFilterValue = view?.anyFieldFilterValue ?? null;
|
||||
}
|
||||
|
||||
const { recordGqlOperationFilter: anyFieldFilter } =
|
||||
turnAnyFieldFilterIntoRecordGqlFilter({
|
||||
fields,
|
||||
filterValue: view?.anyFieldFilterValue ?? '',
|
||||
filterValue: viewAnyFieldFilterValue ?? '',
|
||||
});
|
||||
|
||||
appliedFilters = combineFilters([
|
||||
|
||||
@@ -9,6 +9,11 @@ import {
|
||||
type RelationLoaderPayload,
|
||||
type ViewFieldGroupsByViewIdLoaderPayload,
|
||||
type ViewFieldsByViewFieldGroupIdLoaderPayload,
|
||||
type ViewFieldsByViewIdLoaderPayload,
|
||||
type ViewFilterGroupsByViewIdLoaderPayload,
|
||||
type ViewFiltersByViewIdLoaderPayload,
|
||||
type ViewGroupsByViewIdLoaderPayload,
|
||||
type ViewSortsByViewIdLoaderPayload,
|
||||
} from 'src/engine/dataloaders/dataloader.service';
|
||||
import { type FieldMetadataDTO } from 'src/engine/metadata-modules/field-metadata/dtos/field-metadata.dto';
|
||||
import { type RelationDTO } from 'src/engine/metadata-modules/field-metadata/dtos/relation.dto';
|
||||
@@ -17,6 +22,10 @@ import { type IndexMetadataDTO } from 'src/engine/metadata-modules/index-metadat
|
||||
import { type ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
import { type ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { type ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { type ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto';
|
||||
import { type ViewFilterDTO } from 'src/engine/metadata-modules/view-filter/dtos/view-filter.dto';
|
||||
import { type ViewGroupDTO } from 'src/engine/metadata-modules/view-group/dtos/view-group.dto';
|
||||
import { type ViewSortDTO } from 'src/engine/metadata-modules/view-sort/dtos/view-sort.dto';
|
||||
|
||||
export interface IDataloaders {
|
||||
relationLoader: DataLoader<RelationLoaderPayload, RelationDTO | null>;
|
||||
@@ -55,4 +64,29 @@ export interface IDataloaders {
|
||||
ViewFieldsByViewFieldGroupIdLoaderPayload,
|
||||
ViewFieldDTO[]
|
||||
>;
|
||||
|
||||
viewFieldsByViewIdLoader: DataLoader<
|
||||
ViewFieldsByViewIdLoaderPayload,
|
||||
ViewFieldDTO[]
|
||||
>;
|
||||
|
||||
viewFiltersByViewIdLoader: DataLoader<
|
||||
ViewFiltersByViewIdLoaderPayload,
|
||||
ViewFilterDTO[]
|
||||
>;
|
||||
|
||||
viewSortsByViewIdLoader: DataLoader<
|
||||
ViewSortsByViewIdLoaderPayload,
|
||||
ViewSortDTO[]
|
||||
>;
|
||||
|
||||
viewGroupsByViewIdLoader: DataLoader<
|
||||
ViewGroupsByViewIdLoaderPayload,
|
||||
ViewGroupDTO[]
|
||||
>;
|
||||
|
||||
viewFilterGroupsByViewIdLoader: DataLoader<
|
||||
ViewFilterGroupsByViewIdLoaderPayload,
|
||||
ViewFilterGroupDTO[]
|
||||
>;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ import { fromFlatObjectMetadataToObjectMetadataDto } from 'src/engine/metadata-m
|
||||
import { getMorphNameFromMorphFieldMetadataName } from 'src/engine/metadata-modules/flat-object-metadata/utils/get-morph-name-from-morph-field-metadata-name.util';
|
||||
import { fromFlatViewFieldGroupToViewFieldGroupDto } from 'src/engine/metadata-modules/view-field-group/utils/from-flat-view-field-group-to-view-field-group-dto.util';
|
||||
import { fromFlatViewFieldToViewFieldDto } from 'src/engine/metadata-modules/view-field/utils/from-flat-view-field-to-view-field-dto.util';
|
||||
import { fromFlatViewFilterToViewFilterDto } from 'src/engine/metadata-modules/view-filter/utils/from-flat-view-filter-to-view-filter-dto.util';
|
||||
import { fromFlatViewFilterGroupToViewFilterGroupDto } from 'src/engine/metadata-modules/view-filter-group/utils/from-flat-view-filter-group-to-view-filter-group-dto.util';
|
||||
import { fromFlatViewGroupToViewGroupDto } from 'src/engine/metadata-modules/view-group/utils/from-flat-view-group-to-view-group-dto.util';
|
||||
import { fromFlatViewSortToViewSortDto } from 'src/engine/metadata-modules/view-sort/utils/from-flat-view-sort-to-view-sort-dto.util';
|
||||
import { type IndexFieldMetadataDTO } from 'src/engine/metadata-modules/index-metadata/dtos/index-field-metadata.dto';
|
||||
import { type IndexMetadataDTO } from 'src/engine/metadata-modules/index-metadata/dtos/index-metadata.dto';
|
||||
import { ObjectMetadataDTO } from 'src/engine/metadata-modules/object-metadata/dtos/object-metadata.dto';
|
||||
@@ -84,6 +88,31 @@ export type ViewFieldsByViewFieldGroupIdLoaderPayload = {
|
||||
viewFieldGroupId: string;
|
||||
};
|
||||
|
||||
export type ViewFieldsByViewIdLoaderPayload = {
|
||||
workspaceId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export type ViewFiltersByViewIdLoaderPayload = {
|
||||
workspaceId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export type ViewSortsByViewIdLoaderPayload = {
|
||||
workspaceId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export type ViewGroupsByViewIdLoaderPayload = {
|
||||
workspaceId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
export type ViewFilterGroupsByViewIdLoaderPayload = {
|
||||
workspaceId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
export class DataloaderService {
|
||||
constructor(
|
||||
@@ -102,6 +131,12 @@ export class DataloaderService {
|
||||
this.createViewFieldGroupsByViewIdLoader();
|
||||
const viewFieldsByViewFieldGroupIdLoader =
|
||||
this.createViewFieldsByViewFieldGroupIdLoader();
|
||||
const viewFieldsByViewIdLoader = this.createViewFieldsByViewIdLoader();
|
||||
const viewFiltersByViewIdLoader = this.createViewFiltersByViewIdLoader();
|
||||
const viewSortsByViewIdLoader = this.createViewSortsByViewIdLoader();
|
||||
const viewGroupsByViewIdLoader = this.createViewGroupsByViewIdLoader();
|
||||
const viewFilterGroupsByViewIdLoader =
|
||||
this.createViewFilterGroupsByViewIdLoader();
|
||||
|
||||
return {
|
||||
relationLoader,
|
||||
@@ -112,6 +147,11 @@ export class DataloaderService {
|
||||
objectMetadataLoader,
|
||||
viewFieldGroupsByViewIdLoader,
|
||||
viewFieldsByViewFieldGroupIdLoader,
|
||||
viewFieldsByViewIdLoader,
|
||||
viewFiltersByViewIdLoader,
|
||||
viewSortsByViewIdLoader,
|
||||
viewGroupsByViewIdLoader,
|
||||
viewFilterGroupsByViewIdLoader,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -609,4 +649,181 @@ export class DataloaderService {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createViewFieldsByViewIdLoader() {
|
||||
return new DataLoader<
|
||||
ViewFieldsByViewIdLoaderPayload,
|
||||
ReturnType<typeof fromFlatViewFieldToViewFieldDto>[]
|
||||
>(async (dataLoaderParams: ViewFieldsByViewIdLoaderPayload[]) => {
|
||||
const workspaceId = dataLoaderParams[0].workspaceId;
|
||||
|
||||
const { flatViewMaps, flatViewFieldMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps', 'flatViewFieldMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return dataLoaderParams.map(({ viewId }) => {
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewId,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFieldIds,
|
||||
flatEntityMaps: flatViewFieldMaps,
|
||||
})
|
||||
.filter((flatViewField) => flatViewField.deletedAt === null)
|
||||
.map(fromFlatViewFieldToViewFieldDto);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createViewFiltersByViewIdLoader() {
|
||||
return new DataLoader<
|
||||
ViewFiltersByViewIdLoaderPayload,
|
||||
ReturnType<typeof fromFlatViewFilterToViewFilterDto>[]
|
||||
>(async (dataLoaderParams: ViewFiltersByViewIdLoaderPayload[]) => {
|
||||
const workspaceId = dataLoaderParams[0].workspaceId;
|
||||
|
||||
const { flatViewMaps, flatViewFilterMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps', 'flatViewFilterMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return dataLoaderParams.map(({ viewId }) => {
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewId,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFilterIds,
|
||||
flatEntityMaps: flatViewFilterMaps,
|
||||
})
|
||||
.filter((flatViewFilter) => flatViewFilter.deletedAt === null)
|
||||
.map(fromFlatViewFilterToViewFilterDto);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createViewSortsByViewIdLoader() {
|
||||
return new DataLoader<
|
||||
ViewSortsByViewIdLoaderPayload,
|
||||
ReturnType<typeof fromFlatViewSortToViewSortDto>[]
|
||||
>(async (dataLoaderParams: ViewSortsByViewIdLoaderPayload[]) => {
|
||||
const workspaceId = dataLoaderParams[0].workspaceId;
|
||||
|
||||
const { flatViewMaps, flatViewSortMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps', 'flatViewSortMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return dataLoaderParams.map(({ viewId }) => {
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewId,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewSortIds,
|
||||
flatEntityMaps: flatViewSortMaps,
|
||||
})
|
||||
.filter((flatViewSort) => flatViewSort.deletedAt === null)
|
||||
.map(fromFlatViewSortToViewSortDto);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createViewGroupsByViewIdLoader() {
|
||||
return new DataLoader<
|
||||
ViewGroupsByViewIdLoaderPayload,
|
||||
ReturnType<typeof fromFlatViewGroupToViewGroupDto>[]
|
||||
>(async (dataLoaderParams: ViewGroupsByViewIdLoaderPayload[]) => {
|
||||
const workspaceId = dataLoaderParams[0].workspaceId;
|
||||
|
||||
const { flatViewMaps, flatViewGroupMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps', 'flatViewGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return dataLoaderParams.map(({ viewId }) => {
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewId,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewGroupIds,
|
||||
flatEntityMaps: flatViewGroupMaps,
|
||||
})
|
||||
.filter((flatViewGroup) => flatViewGroup.deletedAt === null)
|
||||
.map(fromFlatViewGroupToViewGroupDto);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private createViewFilterGroupsByViewIdLoader() {
|
||||
return new DataLoader<
|
||||
ViewFilterGroupsByViewIdLoaderPayload,
|
||||
ReturnType<typeof fromFlatViewFilterGroupToViewFilterGroupDto>[]
|
||||
>(async (dataLoaderParams: ViewFilterGroupsByViewIdLoaderPayload[]) => {
|
||||
const workspaceId = dataLoaderParams[0].workspaceId;
|
||||
|
||||
const { flatViewMaps, flatViewFilterGroupMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps', 'flatViewFilterGroupMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return dataLoaderParams.map(({ viewId }) => {
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: viewId,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFilterGroupIds,
|
||||
flatEntityMaps: flatViewFilterGroupMaps,
|
||||
})
|
||||
.filter(
|
||||
(flatViewFilterGroup) => flatViewFilterGroup.deletedAt === null,
|
||||
)
|
||||
.map(fromFlatViewFilterGroupToViewFilterGroupDto);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+6
-3
@@ -60,12 +60,15 @@ export class ViewController {
|
||||
@Query('objectMetadataId') objectMetadataId?: string,
|
||||
): Promise<ViewDTO[]> {
|
||||
const views = objectMetadataId
|
||||
? await this.viewService.findByObjectMetadataId(
|
||||
? await this.viewService.findByObjectMetadataIdWithRelations(
|
||||
workspace.id,
|
||||
objectMetadataId,
|
||||
userWorkspaceId,
|
||||
)
|
||||
: await this.viewService.findByWorkspaceId(workspace.id, userWorkspaceId);
|
||||
: await this.viewService.findByWorkspaceIdWithRelations(
|
||||
workspace.id,
|
||||
userWorkspaceId,
|
||||
);
|
||||
|
||||
return this.processViewsWithTemplates(views, workspace.id, locale);
|
||||
}
|
||||
@@ -77,7 +80,7 @@ export class ViewController {
|
||||
@RequestLocale() locale: keyof typeof APP_LOCALES | undefined,
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
): Promise<ViewDTO> {
|
||||
const view = await this.viewService.findById(id, workspace.id);
|
||||
const view = await this.viewService.findByIdWithRelations(id, workspace.id);
|
||||
|
||||
if (!isDefined(view)) {
|
||||
throw new ViewException(
|
||||
|
||||
+26
-44
@@ -8,7 +8,6 @@ import {
|
||||
ResolveField,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { isArray } from '@sniptt/guards';
|
||||
import { ViewType, ViewVisibility } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@@ -25,23 +24,17 @@ import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { resolveObjectMetadataStandardOverride } from 'src/engine/metadata-modules/object-metadata/utils/resolve-object-metadata-standard-override.util';
|
||||
import { ViewFieldGroupDTO } from 'src/engine/metadata-modules/view-field-group/dtos/view-field-group.dto';
|
||||
import { ViewFieldDTO } from 'src/engine/metadata-modules/view-field/dtos/view-field.dto';
|
||||
import { ViewFieldService } from 'src/engine/metadata-modules/view-field/services/view-field.service';
|
||||
import { ViewFilterGroupDTO } from 'src/engine/metadata-modules/view-filter-group/dtos/view-filter-group.dto';
|
||||
import { ViewFilterGroupService } from 'src/engine/metadata-modules/view-filter-group/services/view-filter-group.service';
|
||||
import { ViewFilterDTO } from 'src/engine/metadata-modules/view-filter/dtos/view-filter.dto';
|
||||
import { ViewFilterService } from 'src/engine/metadata-modules/view-filter/services/view-filter.service';
|
||||
import { ViewGroupDTO } from 'src/engine/metadata-modules/view-group/dtos/view-group.dto';
|
||||
import { ViewGroupService } from 'src/engine/metadata-modules/view-group/services/view-group.service';
|
||||
import { CreateViewPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/create-view-permission.guard';
|
||||
import { DeleteViewPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/delete-view-permission.guard';
|
||||
import { DestroyViewPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/destroy-view-permission.guard';
|
||||
import { UpdateViewPermissionGuard } from 'src/engine/metadata-modules/view-permissions/guards/update-view-permission.guard';
|
||||
import { ViewSortDTO } from 'src/engine/metadata-modules/view-sort/dtos/view-sort.dto';
|
||||
import { ViewSortService } from 'src/engine/metadata-modules/view-sort/services/view-sort.service';
|
||||
import { CreateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/create-view.input';
|
||||
import { UpdateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/update-view.input';
|
||||
import { ViewDTO } from 'src/engine/metadata-modules/view/dtos/view.dto';
|
||||
import { ViewEntity } from 'src/engine/metadata-modules/view/entities/view.entity';
|
||||
import { ViewService } from 'src/engine/metadata-modules/view/services/view.service';
|
||||
import { ViewGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/view/utils/view-graphql-api-exception.filter';
|
||||
|
||||
@@ -51,13 +44,7 @@ import { ViewGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/view/
|
||||
export class ViewResolver {
|
||||
constructor(
|
||||
private readonly viewService: ViewService,
|
||||
private readonly viewFilterService: ViewFilterService,
|
||||
private readonly viewFilterGroupService: ViewFilterGroupService,
|
||||
private readonly viewSortService: ViewSortService,
|
||||
private readonly viewGroupService: ViewGroupService,
|
||||
private readonly i18nService: I18nService,
|
||||
|
||||
private readonly viewFieldService: ViewFieldService,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => String)
|
||||
@@ -114,7 +101,7 @@ export class ViewResolver {
|
||||
objectMetadataId?: string,
|
||||
@Args('viewTypes', { type: () => [ViewType], nullable: true })
|
||||
viewTypes?: ViewType[],
|
||||
): Promise<ViewEntity[]> {
|
||||
): Promise<ViewDTO[]> {
|
||||
if (objectMetadataId) {
|
||||
return this.viewService.findByObjectMetadataId(
|
||||
workspace.id,
|
||||
@@ -143,7 +130,6 @@ export class ViewResolver {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Do not apply list visibility filtering here: unlisted views are accessible by link
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -211,61 +197,61 @@ export class ViewResolver {
|
||||
@ResolveField(() => [ViewFieldDTO])
|
||||
async viewFields(
|
||||
@Parent() view: ViewDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewFields)) {
|
||||
return view.viewFields;
|
||||
}
|
||||
|
||||
return this.viewFieldService.findByViewId(workspace.id, view.id);
|
||||
return context.loaders.viewFieldsByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewFilterDTO])
|
||||
async viewFilters(
|
||||
@Parent() view: ViewDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewFilters)) {
|
||||
return view.viewFilters;
|
||||
}
|
||||
|
||||
return this.viewFilterService.findByViewId(workspace.id, view.id);
|
||||
return context.loaders.viewFiltersByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewFilterGroupDTO])
|
||||
async viewFilterGroups(
|
||||
@Parent() view: ViewDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewFilterGroups)) {
|
||||
return view.viewFilterGroups;
|
||||
}
|
||||
|
||||
return this.viewFilterGroupService.findByViewId(workspace.id, view.id);
|
||||
return context.loaders.viewFilterGroupsByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewSortDTO])
|
||||
async viewSorts(
|
||||
@Parent() view: ViewDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewSorts)) {
|
||||
return view.viewSorts;
|
||||
}
|
||||
|
||||
return this.viewSortService.findByViewId(workspace.id, view.id);
|
||||
return context.loaders.viewSortsByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewGroupDTO])
|
||||
async viewGroups(
|
||||
@Parent() view: ViewDTO,
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewGroups)) {
|
||||
return view.viewGroups;
|
||||
}
|
||||
|
||||
return this.viewGroupService.findByViewId(workspace.id, view.id);
|
||||
return context.loaders.viewGroupsByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => [ViewFieldGroupDTO])
|
||||
@@ -274,10 +260,6 @@ export class ViewResolver {
|
||||
@Context() context: { loaders: IDataloaders },
|
||||
@AuthWorkspace() workspace: WorkspaceEntity,
|
||||
) {
|
||||
if (isArray(view.viewFieldGroups)) {
|
||||
return view.viewFieldGroups;
|
||||
}
|
||||
|
||||
return context.loaders.viewFieldGroupsByViewIdLoader.load({
|
||||
workspaceId: workspace.id,
|
||||
viewId: view.id,
|
||||
|
||||
+6
-6
@@ -65,7 +65,7 @@ describe('ViewQueryParamsService', () => {
|
||||
{
|
||||
provide: ViewService,
|
||||
useValue: {
|
||||
findById: jest.fn(),
|
||||
findByIdWithRelations: jest.fn(),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -98,7 +98,7 @@ describe('ViewQueryParamsService', () => {
|
||||
|
||||
describe('resolveViewToQueryParams', () => {
|
||||
it('should throw error when view is not found', async () => {
|
||||
viewService.findById.mockResolvedValue(null);
|
||||
viewService.findByIdWithRelations.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
viewQueryParamsService.resolveViewToQueryParams(
|
||||
@@ -120,7 +120,7 @@ describe('ViewQueryParamsService', () => {
|
||||
viewSorts: [],
|
||||
};
|
||||
|
||||
viewService.findById.mockResolvedValue(mockView as any);
|
||||
viewService.findByIdWithRelations.mockResolvedValue(mockView as any);
|
||||
flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps.mockResolvedValue(
|
||||
{
|
||||
flatObjectMetadataMaps: mockFlatObjectMetadataMaps,
|
||||
@@ -168,7 +168,7 @@ describe('ViewQueryParamsService', () => {
|
||||
viewSorts: [],
|
||||
};
|
||||
|
||||
viewService.findById.mockResolvedValue(mockView as any);
|
||||
viewService.findByIdWithRelations.mockResolvedValue(mockView as any);
|
||||
flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps.mockResolvedValue(
|
||||
{
|
||||
flatObjectMetadataMaps: mockFlatObjectMetadataMaps,
|
||||
@@ -204,7 +204,7 @@ describe('ViewQueryParamsService', () => {
|
||||
],
|
||||
};
|
||||
|
||||
viewService.findById.mockResolvedValue(mockView as any);
|
||||
viewService.findByIdWithRelations.mockResolvedValue(mockView as any);
|
||||
flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps.mockResolvedValue(
|
||||
{
|
||||
flatObjectMetadataMaps: mockFlatObjectMetadataMaps,
|
||||
@@ -251,7 +251,7 @@ describe('ViewQueryParamsService', () => {
|
||||
viewSorts: [],
|
||||
};
|
||||
|
||||
viewService.findById.mockResolvedValue(mockView as any);
|
||||
viewService.findByIdWithRelations.mockResolvedValue(mockView as any);
|
||||
flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps.mockResolvedValue(
|
||||
{
|
||||
flatObjectMetadataMaps: mockFlatObjectMetadataMaps,
|
||||
|
||||
+4
-1
@@ -46,7 +46,10 @@ export class ViewQueryParamsService {
|
||||
workspaceId: string,
|
||||
currentWorkspaceMemberId?: string,
|
||||
): Promise<ViewQueryParams> {
|
||||
const view = await this.viewService.findById(viewId, workspaceId);
|
||||
const view = await this.viewService.findByIdWithRelations(
|
||||
viewId,
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
if (!view) {
|
||||
throw new Error(`View with id ${viewId} not found`);
|
||||
|
||||
@@ -4,18 +4,27 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { APP_LOCALES, SOURCE_LOCALE } from 'twenty-shared/translations';
|
||||
import { ViewType, ViewVisibility } from 'twenty-shared/types';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { In, IsNull, Repository } from 'typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { I18nService } from 'src/engine/core-modules/i18n/i18n.service';
|
||||
import { generateMessageId } from 'src/engine/core-modules/i18n/utils/generateMessageId';
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { findFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { findFlatEntityByIdInFlatEntityMapsOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-id-in-flat-entity-maps-or-throw.util';
|
||||
import { findFlatEntityByUniversalIdentifierOrThrow } from 'src/engine/metadata-modules/flat-entity/utils/find-flat-entity-by-universal-identifier-or-throw.util';
|
||||
import { findManyFlatEntityByIdInFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/utils/find-many-flat-entity-by-id-in-flat-entity-maps.util';
|
||||
import { type FlatView } from 'src/engine/metadata-modules/flat-view/types/flat-view.type';
|
||||
import { fromCreateViewInputToFlatViewToCreate } from 'src/engine/metadata-modules/flat-view/utils/from-create-view-input-to-flat-view-to-create.util';
|
||||
import { fromDeleteViewInputToFlatViewOrThrow } from 'src/engine/metadata-modules/flat-view/utils/from-delete-view-input-to-flat-view-or-throw.util';
|
||||
import { fromDestroyViewInputToFlatViewOrThrow } from 'src/engine/metadata-modules/flat-view/utils/from-destroy-view-input-to-flat-view-or-throw.util';
|
||||
import { fromUpdateViewInputToFlatViewToUpdateOrThrow } from 'src/engine/metadata-modules/flat-view/utils/from-update-view-input-to-flat-view-to-update-or-throw.util';
|
||||
import { fromFlatViewFieldGroupToViewFieldGroupDto } from 'src/engine/metadata-modules/view-field-group/utils/from-flat-view-field-group-to-view-field-group-dto.util';
|
||||
import { fromFlatViewFieldToViewFieldDto } from 'src/engine/metadata-modules/view-field/utils/from-flat-view-field-to-view-field-dto.util';
|
||||
import { fromFlatViewFilterGroupToViewFilterGroupDto } from 'src/engine/metadata-modules/view-filter-group/utils/from-flat-view-filter-group-to-view-filter-group-dto.util';
|
||||
import { fromFlatViewFilterToViewFilterDto } from 'src/engine/metadata-modules/view-filter/utils/from-flat-view-filter-to-view-filter-dto.util';
|
||||
import { fromFlatViewGroupToViewGroupDto } from 'src/engine/metadata-modules/view-group/utils/from-flat-view-group-to-view-group-dto.util';
|
||||
import { fromFlatViewSortToViewSortDto } from 'src/engine/metadata-modules/view-sort/utils/from-flat-view-sort-to-view-sort-dto.util';
|
||||
import { CreateViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/create-view.input';
|
||||
import { DeleteViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/delete-view.input';
|
||||
import { DestroyViewInput } from 'src/engine/metadata-modules/view/dtos/inputs/destroy-view.input';
|
||||
@@ -372,42 +381,73 @@ export class ViewService {
|
||||
return viewName;
|
||||
}
|
||||
|
||||
private isViewVisibleToUser(
|
||||
view: {
|
||||
visibility: ViewVisibility;
|
||||
createdByUserWorkspaceId: string | null;
|
||||
},
|
||||
userWorkspaceId?: string,
|
||||
): boolean {
|
||||
if (view.visibility === ViewVisibility.WORKSPACE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (
|
||||
view.visibility === ViewVisibility.UNLISTED &&
|
||||
isDefined(userWorkspaceId) &&
|
||||
view.createdByUserWorkspaceId === userWorkspaceId
|
||||
);
|
||||
}
|
||||
|
||||
private async getFilteredFlatViews({
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
userWorkspaceId,
|
||||
viewTypes,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
objectMetadataId?: string;
|
||||
userWorkspaceId?: string;
|
||||
viewTypes?: ViewType[];
|
||||
}): Promise<FlatView[]> {
|
||||
const { flatViewMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
return Object.values(flatViewMaps.byUniversalIdentifier)
|
||||
.filter(isDefined)
|
||||
.filter((flatView) => flatView.workspaceId === workspaceId)
|
||||
.filter(
|
||||
(flatView) =>
|
||||
!objectMetadataId || flatView.objectMetadataId === objectMetadataId,
|
||||
)
|
||||
.filter((flatView) => flatView.deletedAt === null)
|
||||
.filter(
|
||||
(flatView) =>
|
||||
!viewTypes ||
|
||||
viewTypes.length === 0 ||
|
||||
viewTypes.includes(flatView.type),
|
||||
)
|
||||
.filter((flatView) => this.isViewVisibleToUser(flatView, userWorkspaceId))
|
||||
.sort((a, b) => a.position - b.position);
|
||||
}
|
||||
|
||||
async findByWorkspaceId(
|
||||
workspaceId: string,
|
||||
userWorkspaceId?: string,
|
||||
viewTypes?: ViewType[],
|
||||
): Promise<ViewEntity[]> {
|
||||
const views = await this.viewRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
deletedAt: IsNull(),
|
||||
...(viewTypes && viewTypes.length > 0 && { type: In(viewTypes) }),
|
||||
},
|
||||
order: { position: 'ASC' },
|
||||
relations: [
|
||||
'workspace',
|
||||
'viewFields',
|
||||
'viewFilters',
|
||||
'viewSorts',
|
||||
'viewGroups',
|
||||
'viewFilterGroups',
|
||||
],
|
||||
): Promise<ViewDTO[]> {
|
||||
const flatViews = await this.getFilteredFlatViews({
|
||||
workspaceId,
|
||||
userWorkspaceId,
|
||||
viewTypes,
|
||||
});
|
||||
|
||||
return views.filter((view) => {
|
||||
if (view.visibility === ViewVisibility.WORKSPACE) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
view.visibility === ViewVisibility.UNLISTED &&
|
||||
isDefined(userWorkspaceId) &&
|
||||
view.createdByUserWorkspaceId === userWorkspaceId
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
return flatViews.map(fromFlatViewToViewDto);
|
||||
}
|
||||
|
||||
async findByObjectMetadataId(
|
||||
@@ -415,60 +455,170 @@ export class ViewService {
|
||||
objectMetadataId: string,
|
||||
userWorkspaceId?: string,
|
||||
viewTypes?: ViewType[],
|
||||
): Promise<ViewEntity[]> {
|
||||
const views = await this.viewRepository.find({
|
||||
where: {
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
deletedAt: IsNull(),
|
||||
...(viewTypes && viewTypes.length > 0 && { type: In(viewTypes) }),
|
||||
},
|
||||
order: { position: 'ASC' },
|
||||
relations: [
|
||||
'workspace',
|
||||
'viewFields',
|
||||
'viewFilters',
|
||||
'viewSorts',
|
||||
'viewGroups',
|
||||
'viewFilterGroups',
|
||||
],
|
||||
): Promise<ViewDTO[]> {
|
||||
const flatViews = await this.getFilteredFlatViews({
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
userWorkspaceId,
|
||||
viewTypes,
|
||||
});
|
||||
|
||||
// Apply visibility filtering
|
||||
return views.filter((view) => {
|
||||
if (view.visibility === ViewVisibility.WORKSPACE) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
view.visibility === ViewVisibility.UNLISTED &&
|
||||
isDefined(userWorkspaceId) &&
|
||||
view.createdByUserWorkspaceId === userWorkspaceId
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return flatViews.map(fromFlatViewToViewDto);
|
||||
}
|
||||
|
||||
return false;
|
||||
async findById(id: string, workspaceId: string): Promise<ViewDTO | null> {
|
||||
const { flatViewMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView) || flatView.deletedAt !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return fromFlatViewToViewDto(flatView);
|
||||
}
|
||||
|
||||
async findManyWithRelationsFromCache(
|
||||
flatViews: FlatView[],
|
||||
workspaceId: string,
|
||||
): Promise<ViewDTO[]> {
|
||||
const {
|
||||
flatViewFieldMaps,
|
||||
flatViewFieldGroupMaps,
|
||||
flatViewFilterMaps,
|
||||
flatViewFilterGroupMaps,
|
||||
flatViewSortMaps,
|
||||
flatViewGroupMaps,
|
||||
} =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: [
|
||||
'flatViewFieldMaps',
|
||||
'flatViewFieldGroupMaps',
|
||||
'flatViewFilterMaps',
|
||||
'flatViewFilterGroupMaps',
|
||||
'flatViewSortMaps',
|
||||
'flatViewGroupMaps',
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
return flatViews.map((flatView) => {
|
||||
const viewDto = fromFlatViewToViewDto(flatView);
|
||||
|
||||
viewDto.viewFields = findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFieldIds,
|
||||
flatEntityMaps: flatViewFieldMaps,
|
||||
})
|
||||
.filter((flatEntity) => flatEntity.deletedAt === null)
|
||||
.map(fromFlatViewFieldToViewFieldDto);
|
||||
|
||||
viewDto.viewFieldGroups = findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFieldGroupIds,
|
||||
flatEntityMaps: flatViewFieldGroupMaps,
|
||||
})
|
||||
.filter((flatEntity) => flatEntity.deletedAt === null)
|
||||
.map(fromFlatViewFieldGroupToViewFieldGroupDto);
|
||||
|
||||
viewDto.viewFilters = findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFilterIds,
|
||||
flatEntityMaps: flatViewFilterMaps,
|
||||
})
|
||||
.filter((flatEntity) => flatEntity.deletedAt === null)
|
||||
.map(fromFlatViewFilterToViewFilterDto);
|
||||
|
||||
viewDto.viewFilterGroups = findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewFilterGroupIds,
|
||||
flatEntityMaps: flatViewFilterGroupMaps,
|
||||
})
|
||||
.filter((flatEntity) => flatEntity.deletedAt === null)
|
||||
.map(fromFlatViewFilterGroupToViewFilterGroupDto);
|
||||
|
||||
viewDto.viewSorts = findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewSortIds,
|
||||
flatEntityMaps: flatViewSortMaps,
|
||||
})
|
||||
.filter((flatEntity) => flatEntity.deletedAt === null)
|
||||
.map(fromFlatViewSortToViewSortDto);
|
||||
|
||||
viewDto.viewGroups = findManyFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityIds: flatView.viewGroupIds,
|
||||
flatEntityMaps: flatViewGroupMaps,
|
||||
})
|
||||
.filter((flatEntity) => flatEntity.deletedAt === null)
|
||||
.map(fromFlatViewGroupToViewGroupDto);
|
||||
|
||||
return viewDto;
|
||||
});
|
||||
}
|
||||
|
||||
async findById(id: string, workspaceId: string): Promise<ViewEntity | null> {
|
||||
const view = await this.viewRepository.findOne({
|
||||
where: {
|
||||
id,
|
||||
workspaceId,
|
||||
deletedAt: IsNull(),
|
||||
},
|
||||
relations: [
|
||||
'workspace',
|
||||
'viewFields',
|
||||
'viewFilters',
|
||||
'viewSorts',
|
||||
'viewGroups',
|
||||
'viewFilterGroups',
|
||||
],
|
||||
async findByWorkspaceIdWithRelations(
|
||||
workspaceId: string,
|
||||
userWorkspaceId?: string,
|
||||
viewTypes?: ViewType[],
|
||||
): Promise<ViewDTO[]> {
|
||||
const flatViews = await this.getFilteredFlatViews({
|
||||
workspaceId,
|
||||
userWorkspaceId,
|
||||
viewTypes,
|
||||
});
|
||||
|
||||
return view || null;
|
||||
return this.findManyWithRelationsFromCache(flatViews, workspaceId);
|
||||
}
|
||||
|
||||
async findByObjectMetadataIdWithRelations(
|
||||
workspaceId: string,
|
||||
objectMetadataId: string,
|
||||
userWorkspaceId?: string,
|
||||
viewTypes?: ViewType[],
|
||||
): Promise<ViewDTO[]> {
|
||||
const flatViews = await this.getFilteredFlatViews({
|
||||
workspaceId,
|
||||
objectMetadataId,
|
||||
userWorkspaceId,
|
||||
viewTypes,
|
||||
});
|
||||
|
||||
return this.findManyWithRelationsFromCache(flatViews, workspaceId);
|
||||
}
|
||||
|
||||
async findByIdWithRelations(
|
||||
id: string,
|
||||
workspaceId: string,
|
||||
): Promise<ViewDTO | null> {
|
||||
const { flatViewMaps } =
|
||||
await this.flatEntityMapsCacheService.getOrRecomputeManyOrAllFlatEntityMaps(
|
||||
{
|
||||
workspaceId,
|
||||
flatMapsKeys: ['flatViewMaps'],
|
||||
},
|
||||
);
|
||||
|
||||
const flatView = findFlatEntityByIdInFlatEntityMaps({
|
||||
flatEntityId: id,
|
||||
flatEntityMaps: flatViewMaps,
|
||||
});
|
||||
|
||||
if (!isDefined(flatView) || flatView.deletedAt !== null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const results = await this.findManyWithRelationsFromCache(
|
||||
[flatView],
|
||||
workspaceId,
|
||||
);
|
||||
|
||||
return results[0] ?? null;
|
||||
}
|
||||
|
||||
async findByIdIncludingDeleted(
|
||||
|
||||
@@ -8,10 +8,6 @@ import { FlatViewModule } from 'src/engine/metadata-modules/flat-view/flat-view.
|
||||
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
|
||||
import { UserRoleModule } from 'src/engine/metadata-modules/user-role/user-role.module';
|
||||
import { ViewFieldGroupModule } from 'src/engine/metadata-modules/view-field-group/view-field-group.module';
|
||||
import { ViewFieldModule } from 'src/engine/metadata-modules/view-field/view-field.module';
|
||||
import { ViewFilterGroupModule } from 'src/engine/metadata-modules/view-filter-group/view-filter-group.module';
|
||||
import { ViewFilterModule } from 'src/engine/metadata-modules/view-filter/view-filter.module';
|
||||
import { ViewGroupModule } from 'src/engine/metadata-modules/view-group/view-group.module';
|
||||
import { ViewPermissionsModule } from 'src/engine/metadata-modules/view-permissions/view-permissions.module';
|
||||
import { ViewSortModule } from 'src/engine/metadata-modules/view-sort/view-sort.module';
|
||||
import { ViewController } from 'src/engine/metadata-modules/view/controllers/view.controller';
|
||||
@@ -27,11 +23,7 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([ViewEntity]),
|
||||
ViewPermissionsModule,
|
||||
ViewFieldModule,
|
||||
ViewFieldGroupModule,
|
||||
ViewFilterModule,
|
||||
ViewFilterGroupModule,
|
||||
ViewGroupModule,
|
||||
ViewSortModule,
|
||||
I18nModule,
|
||||
ApplicationModule,
|
||||
|
||||
Reference in New Issue
Block a user