diff --git a/backend/src/api/public/v1/ossprey/packageScatter.ts b/backend/src/api/public/v1/ossprey/packageScatter.ts index de79b8d69f..aafd96c84e 100644 --- a/backend/src/api/public/v1/ossprey/packageScatter.ts +++ b/backend/src/api/public/v1/ossprey/packageScatter.ts @@ -9,8 +9,21 @@ import { validateOrThrow } from '@/utils/validation' import { STEWARDSHIP_STATUS_VALUES } from '../packages/types' +const statusEnum = z.enum(STEWARDSHIP_STATUS_VALUES) + +function normalizeToArray(v: unknown): unknown[] | undefined { + if (v === undefined) return undefined + if (Array.isArray(v)) return v + if (typeof v === 'string' && v.includes(',')) + return v + .split(',') + .map((s) => s.trim()) + .filter(Boolean) + return [v] +} + const scatterQuerySchema = z.object({ - status: z.enum(STEWARDSHIP_STATUS_VALUES).optional(), + status: z.preprocess(normalizeToArray, z.array(statusEnum).min(1)).optional(), }) export async function packageScatterHandler(req: Request, res: Response): Promise { diff --git a/services/libs/data-access-layer/src/osspckgs/api.ts b/services/libs/data-access-layer/src/osspckgs/api.ts index 7df7453690..ed61c1834d 100644 --- a/services/libs/data-access-layer/src/osspckgs/api.ts +++ b/services/libs/data-access-layer/src/osspckgs/api.ts @@ -667,17 +667,16 @@ export interface ScatterPoint { export async function listPackagesForScatter( qx: QueryExecutor, - options: { status?: string } = {}, + options: { status?: string[] } = {}, ): Promise { const { status } = options // 'unassigned' covers packages with no stewardship row (s.id IS NULL) in addition - // to rows explicitly marked unassigned. All other statuses filter via s.status directly. + // to rows explicitly marked unassigned. All other statuses filter via s.status = ANY(...). // The query always uses LEFT JOIN — the filter is applied in the WHERE clause, not the join. - const statusFilter = status - ? status === 'unassigned' - ? `AND (s.status = 'unassigned' OR s.id IS NULL)` - : `AND s.status = $(status)` + const includesUnassigned = status?.includes('unassigned') ?? false + const statusFilter = status?.length + ? `AND (s.status = ANY($(status)::text[])${includesUnassigned ? ' OR s.id IS NULL' : ''})` : '' const rows: Array<{