Skip to content

Commit

Permalink
fix(INTERNAL-1408): fix query for parntership projects
Browse files Browse the repository at this point in the history
  • Loading branch information
LamaEats committed Dec 4, 2024
1 parent 5b2252e commit fbf14ae
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 85 deletions.
6 changes: 3 additions & 3 deletions src/components/ProjectGoalList/ProjectGoalList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ interface ProjectGoalListProps {
filterPreset?: FilterById;
partnershipProject?: string[];
showNoGoals?: boolean;
isOnlySubsGoals?: boolean;
askRights?: boolean;
}

const onGoalClickHandler = (e: React.MouseEvent) => {
Expand All @@ -33,7 +33,7 @@ export const ProjectGoalList: FC<ProjectGoalListProps> = ({
filterPreset,
partnershipProject,
showNoGoals,
isOnlySubsGoals,
askRights,
}) => {
const { queryState, setTagsFilterOutside } = useUrlFilterParams({
preset: filterPreset,
Expand All @@ -48,7 +48,7 @@ export const ProjectGoalList: FC<ProjectGoalListProps> = ({
} = trpc.v2.project.getProjectGoalsById.useInfiniteQuery(
{
id,
isOnlySubsGoals,
askRights,
goalsQuery: {
...queryState,
partnershipProject: partnershipProject ?? undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const ProjectListItemConnected: FC<ProjectListItemConnectedProps> = ({
filterPreset={filterPreset}
partnershipProject={partnershipProject}
showNoGoals={showNoGoals}
isOnlySubsGoals={project._onlySubsGoals}
askRights={project._onlySubsGoals}
/>,
)}
</TreeViewElement>
Expand Down
128 changes: 88 additions & 40 deletions trpc/queries/goalV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { decodeUrlDateRange, getDateString } from '@taskany/bricks';
import { db } from '../connection/kysely';
import { QueryWithFilters } from '../../src/schema/common';
import { DB, Role } from '../../generated/kysely/types';
import { calculateProjectRules, ProjectRoles } from '../utils';

import { getUserActivity } from './activity';

Expand Down Expand Up @@ -65,6 +66,34 @@ export const mapSortParamsToTableColumns = <T extends DB, K extends keyof T, R =
return sort.map<OrderByExpression<T, K, R>>(({ key, dir }) => mapToTableColumn[key][dir]);
};

const subSelectUserProejcts = (activityId: string) =>
db
.selectFrom('_projectParticipants')
.select('B')
.where('A', '=', activityId)
.union(db.selectFrom('_projectStargizers').select('B').where('A', '=', activityId))
.union(db.selectFrom('_projectWatchers').select('B').where('A', '=', activityId))
.union(db.selectFrom('Project').select('Project.id as B').where('Project.activityId', '=', activityId));

const subSelectUserGoals = (activityId: string) =>
db
.selectFrom('_goalParticipants')
.select('B')
.where('A', '=', activityId)
.union(db.selectFrom('_goalStargizers').select('B').where('A', '=', activityId))
.union(db.selectFrom('_goalWatchers').select('B').where('A', '=', activityId))
.union(
db
.selectFrom('Goal')
.select('Goal.id as B')
.where(({ or, eb }) =>
or([eb('Goal.activityId', '=', activityId), eb('Goal.ownerId', '=', activityId)]),
),
);

const subSelectPartnershipGoals = (projectId: string) =>
db.selectFrom('_partnershipProjects').select('A').where('B', '=', projectId);

interface GetGoalsQueryParams {
role: Role;
activityId: string;
Expand All @@ -73,6 +102,7 @@ interface GetGoalsQueryParams {
limit?: number;
offset?: number;
goalsQuery?: QueryWithFilters;
readRights?: Array<ProjectRoles>;
}

export const getGoalsQuery = (params: GetGoalsQueryParams) =>
Expand Down Expand Up @@ -190,49 +220,67 @@ export const getGoalsQuery = (params: GetGoalsQueryParams) =>
.as('partnershipProjects'),
])
.where('Goal.archived', 'is not', true)
.where('Goal.projectId', '=', params.projectId)
.where(({ and, or, eb, val, cast, selectFrom }) =>
or([
and([
eb(cast(val(!!params.isOnlySubsGoals), 'boolean'), 'is', false),
eb(
'Goal.id',
'in',
selectFrom('_partnershipProjects').select('A').where('B', '=', params.projectId),
),
.$if(params.readRights == null, (qb) =>
qb.where(({ or, eb }) =>
or([
eb('Goal.projectId', '=', params.projectId),
eb('Goal.id', 'in', subSelectPartnershipGoals(params.projectId)),
]),
and([
eb(cast(val(!!params.isOnlySubsGoals), 'boolean'), 'is', true),
or([
eb('Goal.ownerId', '=', params.activityId),
eb('Goal.activityId', '=', params.activityId),
eb('Goal.id', 'in', ({ selectFrom }) =>
selectFrom('_goalParticipants')
.select('B')
.where('A', '=', params.activityId)
.union(
selectFrom('_goalWatchers').select('B').where('A', '=', params.activityId),
)
.union(
selectFrom('_goalStargizers')
.select('B')
.where('A', '=', params.activityId),
)
.union(
selectFrom('_partnershipProjects')
.select('A as B')
.where(
'B',
'in',
selectFrom('Project')
.select('Project.id')
.where('Project.activityId', '=', params.activityId),
),
),
)
.$if((params.readRights?.length ?? 0) > 0, (qb) =>
qb.where(({ or, selectFrom, eb, and }) => {
if (params.readRights) {
const parsedRights = calculateProjectRules(params.readRights);

if (parsedRights.projectFullAccess) {
return or([
eb('Goal.projectId', '=', params.projectId),
eb('Goal.id', 'in', subSelectPartnershipGoals(params.projectId)),
]);
}

const filteredPartnershipBySubGoalsAndProjects = and([
eb('Goal.projectId', '=', params.projectId),
eb(
'Goal.id',
'in',
selectFrom('_partnershipProjects')
.select('A')
.where(({ ref }) =>
or([
eb(ref('B'), 'in', subSelectUserProejcts(params.activityId)),
eb(ref('A'), 'in', subSelectUserGoals(params.activityId)),
]),
),
),
]),
]),
]),
]);

const filteredPartnershipGoalsToCurrentProject = and([
eb(
'Goal.id',
'in',
selectFrom('_partnershipProjects')
.select('A')
.where('B', '=', params.projectId)
.where('A', 'in', subSelectUserGoals(params.activityId)),
),
]);

const filterPRojectGoalsBySubscribe = and([
eb('Goal.projectId', '=', params.projectId),
eb('Goal.id', 'in', subSelectUserGoals(params.activityId)),
]);

return or([
filteredPartnershipBySubGoalsAndProjects,
filteredPartnershipGoalsToCurrentProject,
filterPRojectGoalsBySubscribe,
]);
}

return and([]);
}),
)
.where(({ or, and, eb, selectFrom, cast, val }) => {
const { goalsQuery } = params;
Expand Down
75 changes: 41 additions & 34 deletions trpc/queries/projectV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -769,7 +769,10 @@ export const getChildrenProjectByParentProjectId = ({ id }: { id: string }) => {
);
};

export const getUserProjects = ({ activityId }: Pick<GetAllProjectsQueryParams, 'activityId'>) => {
export const getUserProjects = ({
activityId,
projectId = '',
}: Pick<GetAllProjectsQueryParams, 'activityId'> & { projectId?: string }) => {
return db
.with('subs_projects', (db) =>
db
Expand Down Expand Up @@ -810,24 +813,20 @@ export const getUserProjects = ({ activityId }: Pick<GetAllProjectsQueryParams,
.selectFrom('Project')
.innerJoin('subs_projects', 'subs_projects.pid', 'Project.id')
.select(['Project.id as pid', 'subs_projects.role'])
.where(({ or, eb }) =>
or([
eb('Project.id', 'in', ({ selectFrom }) => selectFrom('subs_projects').select('pid')),
eb('Project.activityId', '=', activityId),
]),
)
.union((eb) =>
eb.parens(
eb
.selectFrom('_parentChildren')
.innerJoin('subs_projects', 'subs_projects.pid', 'A')
.select(['B as pid', 'subs_projects.role']),
),
eb
.selectFrom('_parentChildren')
.innerJoin('subs_projects', 'subs_projects.pid', 'A')
.select(['B as pid', 'subs_projects.role']),
)
.$if(projectId.length > 0, (qb) => qb.where('Project.id', '=', projectId))
.$castTo<{ pid: string; role: number }>();
};

export const getUserProjectsByGoals = ({ activityId }: Pick<GetAllProjectsQueryParams, 'activityId'>) => {
export const getUserProjectsByGoals = ({
activityId,
projectId = '',
}: Pick<GetAllProjectsQueryParams, 'activityId'> & { projectId?: string }) => {
return db
.with('cte_user_goals', () =>
db
Expand Down Expand Up @@ -876,22 +875,22 @@ export const getUserProjectsByGoals = ({ activityId }: Pick<GetAllProjectsQueryP
.union(
db
.selectFrom('_partnershipProjects')
.innerJoinLateral(
() => getUserProjects({ activityId }).as('cte_user_projects'),
(join) =>
join
.on('role', 'in', [ProjectRoles.project_owner, ProjectRoles.project_participant])
.onRef('_partnershipProjects.B', '=', 'cte_user_projects.pid'),
)
.select(({ cast, val }) => [
'A as gid',
cast<number>(val(ProjectRoles.goal_partner), 'integer').as('role'),
]),
])
.where('_partnershipProjects.B', 'in', () =>
db
.selectFrom(() => getUserProjects({ activityId }).as('user_projects'))
.select('user_projects.pid'),
),
),
)
.selectFrom('Goal')
.innerJoin('cte_user_goals', 'Goal.id', 'cte_user_goals.gid')
.select(['Goal.projectId as pid', 'cte_user_goals.role as role'])
.where('Goal.archived', 'is not', true)
.$if(projectId.length > 0, (qb) => qb.where('Goal.projectId', '=', projectId))
.$castTo<{ pid: string; role: number }>();
};

Expand All @@ -915,16 +914,24 @@ export const getRealDashboardQueryByProjectIds = ({
const values = sql<{ pid: string; full_access: boolean; only_subs: boolean }>`(values ${sql.join(toJoinValues)})`;
const aliasedValues = values.as<'proj_rules'>(sql`proj_rules(pid, full_access, only_subs)`);

const query = db
return db
.with('cte_projects', () => db.selectFrom(aliasedValues).selectAll('proj_rules'))
.selectFrom('Project')
.innerJoin('cte_projects as projectRights', 'projectRights.pid', 'Project.id')
.leftJoinLateral(
({ selectFrom }) =>
selectFrom('_partnershipProjects')
.innerJoin('Goal', 'Goal.id', '_partnershipProjects.A')
.distinctOn('Goal.projectId')
.select('Goal.projectId as pid')
.innerJoinLateral(
({ selectFrom }) =>
selectFrom('Goal')
.select('Goal.projectId')
.where('Goal.archived', 'is not', true)
.whereRef('Goal.id', '=', '_partnershipProjects.A')
.as('goal'),
(join) => join.onTrue(),
)
.distinctOn('goal.projectId')
.select('goal.projectId as pid')
.whereRef('_partnershipProjects.B', '=', 'Project.id')
.as('partnershipProjectIds'),
(join) => join.onTrue(),
Expand All @@ -934,16 +941,18 @@ export const getRealDashboardQueryByProjectIds = ({
selectFrom('Goal')
.select('Goal.id')
.where('Goal.archived', 'is not', true)
.whereRef('Goal.projectId', '=', 'Project.id')
.where(({ and, or, eb, ref, cast }) =>
or([
and([
eb(cast(ref('projectRights.full_access'), 'boolean'), 'is', true),
eb(
'Goal.id',
'in',
selectFrom('_partnershipProjects').select('A').whereRef('B', '=', 'Project.id'),
),
or([
eb('Goal.projectId', '=', ref('Project.id')),
eb(
'Goal.id',
'in',
selectFrom('_partnershipProjects').select('A').whereRef('B', '=', 'Project.id'),
),
]),
]),
and([
eb(cast(ref('projectRights.only_subs'), 'boolean'), 'is', true),
Expand Down Expand Up @@ -1005,6 +1014,4 @@ export const getRealDashboardQueryByProjectIds = ({
.orderBy('Project.updatedAt desc')
.limit(limit)
.offset(offset);

return query;
};
Loading

0 comments on commit fbf14ae

Please sign in to comment.