| 327 | 327 | | |
| 328 | 328 | | /// What every query of work items starts with: the visibility check (a |
| 329 | 329 | | /// member of the workspace, or a reader of the origin), then `repo:` |
| 330 | | − | /// (any repository it is linked to), `org:` (its workspace) and |
| 331 | | − | /// `is:public`/`is:private` (whether its origin is public). |
| 330 | + | /// (any repository it is linked to that the reader may see: one they may |
| 331 | + | /// not is answered as one that does not exist, so neither `repo:` nor |
| 332 | + | /// `-repo:` says a private repository is there), `org:` (its workspace) |
| 333 | + | /// and `is:public`/`is:private` (whether its origin is public). |
| 332 | 334 | | fn item_scope(query: &Query, reader: &Reader) -> Where { |
| 333 | 335 | | let mut out = Where::default(); |
| 334 | 336 | | out.add( |
| ⋯ |
| 336 | 338 | | vec![Param::Text(reader.members_json()), Param::Text(reader.namespaces_json()), Param::Text(reader.granted_json())], |
| 337 | 339 | | ); |
| 338 | 340 | | let linked = "SELECT 1 FROM repos lr WHERE (lr.namespace || '/' || lr.name) IN (SELECT value FROM json_each(?)) AND instr(i.repos, '|' || lr.repo_id || '|') > 0"; |
| 341 | + | let linked = format!("{linked} AND {}", clause("lr")); |
| 342 | + | let named = |names: &[String]| vec![json(names), Param::Text(reader.namespaces_json()), Param::Text(reader.granted_json())]; |
| 339 | 343 | | if !query.repos.include.is_empty() { |
| 340 | | − | out.add(format!("EXISTS ({linked})"), vec![json(&query.repos.include)]); |
| 344 | + | out.add(format!("EXISTS ({linked})"), named(&query.repos.include)); |
| 341 | 345 | | } |
| 342 | 346 | | if !query.repos.exclude.is_empty() { |
| 343 | | − | out.add(format!("NOT EXISTS ({linked})"), vec![json(&query.repos.exclude)]); |
| 347 | + | out.add(format!("NOT EXISTS ({linked})"), named(&query.repos.exclude)); |
| 344 | 348 | | } |
| 345 | 349 | | in_list(&query.owners, "i.workspace", &mut out); |
| 346 | 350 | | match query.visibility { |