diff --git a/app/libs/tenant-query.server.ts b/app/libs/tenant-query.server.ts new file mode 100644 index 00000000..1a96fbd2 --- /dev/null +++ b/app/libs/tenant-query.server.ts @@ -0,0 +1,19 @@ +import type { ExpressionBuilder } from 'kysely' +import type * as TenantDB from '~/app/services/tenant-type' + +/** + * companyGithubUsers.type が Bot でない行のみ残すフィルタ。 + * LEFT JOIN で companyGithubUsers に結合している前提で使う。 + * NULL(未登録ユーザー)も通す。 + */ +export function excludeBots( + eb: ExpressionBuilder< + TenantDB.DB & { companyGithubUsers: TenantDB.CompanyGithubUsers }, + keyof TenantDB.DB | 'companyGithubUsers' + >, +) { + return eb.or([ + eb('companyGithubUsers.type', 'is', null), + eb('companyGithubUsers.type', '!=', 'Bot'), + ]) +} diff --git a/app/routes/$orgSlug/analysis/reviews/+functions/queries.server.ts b/app/routes/$orgSlug/analysis/reviews/+functions/queries.server.ts index 249a706e..f1d6df31 100644 --- a/app/routes/$orgSlug/analysis/reviews/+functions/queries.server.ts +++ b/app/routes/$orgSlug/analysis/reviews/+functions/queries.server.ts @@ -1,4 +1,5 @@ import { sql } from 'kysely' +import { excludeBots } from '~/app/libs/tenant-query.server' import { getTenantDb } from '~/app/services/tenant-db.server' import type { OrganizationId } from '~/app/types/organization' @@ -122,12 +123,7 @@ export const getWipCycleRawData = async ( .$if(teamId != null, (qb) => qb.where('repositories.teamId', '=', teamId as string), ) - .where((eb) => - eb.or([ - eb('companyGithubUsers.type', 'is', null), - eb('companyGithubUsers.type', '!=', 'Bot'), - ]), - ) + .where(excludeBots) .leftJoin('pullRequestFeedbacks', (join) => join .onRef( @@ -188,12 +184,7 @@ export const getPRSizeDistribution = async ( .$if(teamId != null, (qb) => qb.where('repositories.teamId', '=', teamId as string), ) - .where((eb) => - eb.or([ - eb('companyGithubUsers.type', 'is', null), - eb('companyGithubUsers.type', '!=', 'Bot'), - ]), - ) + .where(excludeBots) .leftJoin('pullRequestFeedbacks', (join) => join .onRef( diff --git a/app/routes/$orgSlug/throughput/deployed/+functions/queries.server.ts b/app/routes/$orgSlug/throughput/deployed/+functions/queries.server.ts index 085069ae..786eed05 100644 --- a/app/routes/$orgSlug/throughput/deployed/+functions/queries.server.ts +++ b/app/routes/$orgSlug/throughput/deployed/+functions/queries.server.ts @@ -1,6 +1,7 @@ import { pipe, sortBy } from 'remeda' import { calculateBusinessHours } from '~/app/libs/business-hours' import dayjs from '~/app/libs/dayjs' +import { excludeBots } from '~/app/libs/tenant-query.server' import { getTenantDb } from '~/app/services/tenant-db.server' import type { OrganizationId } from '~/app/types/organization' @@ -31,12 +32,7 @@ export const getDeployedPullRequestReport = async ( .$if(teamId != null, (qb) => qb.where('repositories.teamId', '=', teamId as string), ) - .where((eb) => - eb.or([ - eb('companyGithubUsers.type', 'is', null), - eb('companyGithubUsers.type', '!=', 'Bot'), - ]), - ) + .where(excludeBots) .leftJoin('pullRequestFeedbacks', (join) => join .onRef( diff --git a/app/routes/$orgSlug/throughput/merged/+functions/queries.server.ts b/app/routes/$orgSlug/throughput/merged/+functions/queries.server.ts index f11485e7..5d7a50a6 100644 --- a/app/routes/$orgSlug/throughput/merged/+functions/queries.server.ts +++ b/app/routes/$orgSlug/throughput/merged/+functions/queries.server.ts @@ -1,6 +1,7 @@ import { pipe, sortBy } from 'remeda' import { calculateBusinessHours } from '~/app/libs/business-hours' import dayjs from '~/app/libs/dayjs' +import { excludeBots } from '~/app/libs/tenant-query.server' import { getTenantDb } from '~/app/services/tenant-db.server' import type { OrganizationId } from '~/app/types/organization' @@ -30,12 +31,7 @@ export const getMergedPullRequestReport = async ( .$if(teamId != null, (qb) => qb.where('repositories.teamId', '=', teamId as string), ) - .where((eb) => - eb.or([ - eb('companyGithubUsers.type', 'is', null), - eb('companyGithubUsers.type', '!=', 'Bot'), - ]), - ) + .where(excludeBots) .leftJoin('pullRequestFeedbacks', (join) => join .onRef( diff --git a/app/routes/$orgSlug/throughput/ongoing/+functions/queries.server.ts b/app/routes/$orgSlug/throughput/ongoing/+functions/queries.server.ts index 1550d6f5..b706f97a 100644 --- a/app/routes/$orgSlug/throughput/ongoing/+functions/queries.server.ts +++ b/app/routes/$orgSlug/throughput/ongoing/+functions/queries.server.ts @@ -1,6 +1,7 @@ import { pipe, sortBy } from 'remeda' import { calculateBusinessHours } from '~/app/libs/business-hours' import dayjs from '~/app/libs/dayjs' +import { excludeBots } from '~/app/libs/tenant-query.server' import { getTenantDb } from '~/app/services/tenant-db.server' import type { OrganizationId } from '~/app/types/organization' @@ -33,12 +34,7 @@ export const getOngoingPullRequestReport = async ( ) .where('mergedAt', 'is', null) .where('state', '=', 'open') - .where((eb) => - eb.or([ - eb('companyGithubUsers.type', 'is', null), - eb('companyGithubUsers.type', '!=', 'Bot'), - ]), - ) + .where(excludeBots) .leftJoin('pullRequestFeedbacks', (join) => join .onRef( diff --git a/app/routes/$orgSlug/workload/+functions/stacks.server.ts b/app/routes/$orgSlug/workload/+functions/stacks.server.ts index ff342262..64071722 100644 --- a/app/routes/$orgSlug/workload/+functions/stacks.server.ts +++ b/app/routes/$orgSlug/workload/+functions/stacks.server.ts @@ -1,4 +1,5 @@ import { sql } from 'kysely' +import { excludeBots } from '~/app/libs/tenant-query.server' import { getTenantDb } from '~/app/services/tenant-db.server' import type { OrganizationId } from '~/app/types/organization' @@ -26,12 +27,7 @@ export const getOpenPullRequests = async ( .$if(teamId != null, (qb) => qb.where('repositories.teamId', '=', teamId as string), ) - .where((eb) => - eb.or([ - eb('companyGithubUsers.type', 'is', null), - eb('companyGithubUsers.type', '!=', 'Bot'), - ]), - ) + .where(excludeBots) .select([ 'pullRequests.author', 'pullRequests.number', @@ -48,6 +44,10 @@ export const getOpenPullRequests = async ( select 1 from ${sql.ref('pullRequestReviewers')} where ${sql.ref('pullRequestReviewers.pullRequestNumber')} = ${sql.ref('pullRequests.number')} and ${sql.ref('pullRequestReviewers.repositoryId')} = ${sql.ref('pullRequests.repositoryId')} + and lower(${sql.ref('pullRequestReviewers.reviewer')}) not in ( + select lower(${sql.ref('companyGithubUsers.login')}) from ${sql.ref('companyGithubUsers')} + where ${sql.ref('companyGithubUsers.type')} = 'Bot' + ) )`.as('hasAnyReviewer'), ) .execute() @@ -92,6 +92,7 @@ export const getPendingReviewAssignments = async ( .where('pullRequests.mergedAt', 'is', null) .where('pullRequests.closedAt', 'is', null) .where('pullRequestReviewers.requestedAt', 'is not', null) + .where(excludeBots) .$if(teamId != null, (qb) => qb.where('repositories.teamId', '=', teamId as string), )